#ifndef __BB_PROCESSOR_H__
#define __BB_PROCESSOR_H__

#include <string>
#include <unordered_map>

#include "../data_stream/data_handle.h"
#include "../data_stream/data_stream.h"
namespace bb::processor {

class Processor {
  private:
    bool                              initialized_{false};
    std::string                       name_;
    unsigned int                      call_times_;
    std::shared_ptr<data::DataHandle> data_handle_;
    virtual void                      Script() = 0;

  public:
    Processor(std::string name) : name_(name) {}

  public:
    void Call() {
        if (not initialized_) throw exception::LogicError("Processor [", Name(), "]: not initialized!");
        ++call_times_;
        Script();
    }
    void Init(std::shared_ptr<data::DataHandle> data_handle) {
        initialized_ = true;
        data_handle_ = data_handle;
    }
    void Reset() { initialized_ = false; }
    auto Name() -> std::string { return name_; }
    auto InputValue(std::string name) {
        if (not initialized_) throw exception::LogicError("Processor [", Name(), "]: not initialized!");
        if (data_handle_->InputsData().count(name))
            return data_handle_->InputsData().at(name);
        else
            throw exception::RuntimeError("Processor [", Name(), "]: no such input data stream named: ", name);
    }
    auto InputKeys() -> std::vector<std::string> {
        if (not initialized_) throw exception::LogicError("Processor [", Name(), "]: not initialized!");
        auto result = std::vector<std::string>{};
        for (const auto& [key, _] : data_handle_->InputsData()) result.emplace_back(key);
        return result;
    }
    auto OutputKeys() -> std::vector<std::string> {
        if (not initialized_) throw exception::LogicError("Processor [", Name(), "]: not initialized!");
        auto result = std::vector<std::string>{};
        for (const auto& [key, _] : data_handle_->OutputsData()) result.emplace_back(key);
        return result;
    }
    auto OutputValue(std::string name) {
        if (not initialized_) throw exception::LogicError("Processor [", Name(), "]: not initialized!");
        if (data_handle_->OutputsData().count(name))
            return data_handle_->OutputsData().at(name);
        else
            throw exception::RuntimeError("Processor [", Name(), "]: no such output data stream named: ", name);
    }
};

} // namespace bb::processor

#endif // __BB_PROCESSOR_H__